/*******************************************************************************
 * Copyright (c) 2007 University of Oslo.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     University of Oslo - initial API and implementation
 *******************************************************************************/

package com.cea.papyrus.diagram.sequence.sedi.figures;

import java.util.List;

import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.XYLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.text.FlowPage;
import org.eclipse.draw2d.text.TextFlow;

import com.cea.papyrus.diagraminterchange2.di2.GraphElement;

/**
 * @author Andreas Limyr
 * @author frankd@ifi.uio.no
 */
public class CombinedFragmentFigure extends AnchoringFigure {

    // TODO Remove size preferences from the figure
    private static final Dimension DEFAULT_SIZE = new Dimension(250, 130);
    private static final Dimension MIN_SIZE = new Dimension(100, 50);

    private FlowPage titleFlow;
    private TextFlow stereotypes;
    private TextFlow op;

    public CombinedFragmentFigure() {
        setLayoutManager(new XYLayout());
        setBorder(new FragmentBorder());
        stereotypes = new TextFlow("");
        op = new TextFlow("");
        titleFlow = new FlowPage();
        titleFlow.add(stereotypes);
        titleFlow.add(new TextFlow(" "));
        titleFlow.add(op);
        add(titleFlow);
    }

    /** @Deprecated */
    public Rectangle getPreferredBounds(Rectangle suggestedBounds) {
        int width =
                suggestedBounds.width == 0 ? DEFAULT_SIZE.width
                        : (suggestedBounds.width < MIN_SIZE.width ? MIN_SIZE.width
                                : suggestedBounds.width);
        int height =
                suggestedBounds.height == 0 ? DEFAULT_SIZE.height
                        : (suggestedBounds.height < MIN_SIZE.height ? MIN_SIZE.height
                                : suggestedBounds.height);
        return new Rectangle(suggestedBounds.x, suggestedBounds.y, width, height);
    }

    // TODO Remove - this should be handled by layout handler
    public Dimension getPreferredSize(int w, int h) {
        Dimension prefSize = super.getPreferredSize(w, h);
        Dimension defaultSize = new Dimension(200, 100);
        prefSize.union(defaultSize);
        return prefSize;
    }

    @Override
    protected void paintFigure(Graphics graphics) {
        ((FragmentBorder) getBorder()).setColor(this.getBorderColor());
        ((FragmentBorder) getBorder()).setBackgroundColor(this.getBackgroundColor());
        ((FragmentBorder) getBorder()).paintLabelBackground(this, graphics);
        titleFlow.setFont(this.getFont());
        titleFlow.setForegroundColor(this.getFontColor());

    }

    @Override
    public void validate() {
        if (isValid())
            return;
        super.validate();

        Dimension prefSize = titleFlow.getPreferredSize();
        if (!titleFlow.getSize().equals(prefSize)) {
            titleFlow.setSize(prefSize);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean containsPoint(int x, int y) {
        Rectangle rect = getBounds();
        Rectangle label = op.getBounds();
        // check if point is almost inside the pentagon
        if (x > rect.x && x < (rect.x + label.width + 12)) {
            if (y > rect.y && y < rect.y + label.height + 8) {
                return true;
            }
        }

        // check if point is at the topline of the figure
        if (x > rect.x && x < rect.x + rect.width) {
            if (y > rect.y - 6 && y < rect.y + 6) {
                return true;
            }
        }

        // check if point is at the bottom line of the figure
        if (x > rect.x && x < rect.x + rect.width) {
            if (y > rect.y + rect.height - 6 && y < rect.y + rect.height + 6) {
                return true;
            }
        }

        // check if point is at the left line of the figure
        if (x > rect.x - 6 && x < rect.x + 6) {
            if (y > rect.y && y < rect.y + rect.height) {
                return true;
            }
        }

        // check if point is at the right line of the figure
        if (x > rect.x + rect.width - 6 && x < rect.x + rect.width + 6) {
            if (y > rect.y && y < rect.y + rect.height) {
                return true;
            }
        }

        for (IFigure child : (List<IFigure>) getChildren()) {
            Point local = new Point(x, y);
            translateFromParent(local);
            if (child.containsPoint(local))
                return true;
        }

        return false;
    }

    // TODO Pull up to superclass
    protected boolean useLocalCoordinates() {
        return true;
    }

    // Called by the FragmentBorder to paint a frame label border of the
    // correct size
    public Rectangle getLocalTextBounds() {
        return op.getBounds().getCopy();
    }

    // --- ILabeledFigure ---

    public Rectangle getLabelBounds() {
        Rectangle rect = op.getClientArea().getCopy();
        op.translateToAbsolute(rect);
        return rect;
    }

    public void setLabel(String labelText) {
        op.setText(labelText);
        repaint();
    }

    // --- Anchor contribution ---

    private AnchorPolicy anchorPolicy;

    public AnchorPolicy getAnchorPolicy() {
        if (anchorPolicy == null)
            anchorPolicy = new CombinedFragmentAnchorPolicy(this);
        return anchorPolicy;
    }

    public Rectangle getAnchorContributionBounds(IFigure figure) {
        int start = ((FragmentBorder) getBorder()).getLabelHeight(this);
        return new Rectangle(0, start, getSize().width, getSize().height - start - 3);
    }

    public int[] contributeAnchors(IFigure figure, int y) {
        return new int[] {
                0, getSize().width - 1
        };
    }

    /**
     * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
     */
    @Override
    public void setBounds(Rectangle rect) {
        // TODO Auto-generated method stub
        super.setBounds(rect);
    }

    /**
     * @see com.cea.papyrus.diagram.sequence.sedi.figures.SeDiSubpartFigure#refreshStereotypes(com.cea.papyrus.diagraminterchange2.di2.GraphElement)
     */
    @Override
    public void refreshStereotypes(GraphElement graphElement) {
        super.refreshStereotypes(graphElement);
        this.stereotypes.setText(this.getStereotypesLabel());
    }
}
